import datetime
import time
from itertools import groupby
from operator import itemgetter

import math
from openerp import netsvc
from openerp import tools
from openerp.osv import fields, osv
from openerp.tools.translate import _


class working_shift(osv.osv):
    _name = "working.shift"
    _columns ={
               'name':fields.char('Shift name',size=55,required=True),
               'effective_date':fields.datetime('Effective Date'),
               'hour_start':fields.float('Start Hour', required=True),
               'hour_end':fields.float('End Hour', required=True),
               'employee_ids':fields.many2many('hr.employee', 'employee_working_shift_ref', 'employee_id', 'working_shift_id', 'Employees'),
               }
    def _check_hour(self, cr, uid, ids,context=None):
        for shift in self.browse(cr, uid, ids, context=context):
            if shift.hour_start or  shift.hour_end:
                if shift.hour_start > shift.hour_end:
                    return False
                if shift.hour_start < 0 or shift.hour_start >= 24:
                    return False
                if shift.hour_end < 0 or shift.hour_end >= 24:
                    return False
        return True
    
    _constraints = [
        (_check_hour,"'Start Hour' must less than end hour or 'Start Hour' or 'End Hour' is out of range [0,24].",['hour_start','hour_end']),
    ]
    
working_shift()
class default_day_off(osv.osv):
    _name="default.day.off"
    _columns ={
         'name':fields.char('Name',size=64,required=True),
         'code':fields.char('Code',size=64),
         'date_start':fields.date('Date From'),
         'date_end':fields.date('Date To'),
         'active':fields.boolean('Active'),      
    }
    def _check_date(self, cr, uid, ids,context=None):
        for date in self.browse(cr, uid, ids, context=context):
            if date.date_end < date.date_start:
                return False
        return True
    _constraints = [
        (_check_date, 'Date end must NOT less than Date start', ['date_start','date_end']),
    ]
    _defaults = {
        'active': 1,
    }
default_day_off()

class hr_overtime_status(osv.osv):
    _name = "hr.overtime.status"
    _columns = {
        'name': fields.char('Overtime Type', size=64, required=True, translate=True),
        'categ_id': fields.many2one('crm.meeting.type', 'Meeting Type',
            help='Once a overtime is validated, OpenERP will create a corresponding meeting of this type in the calendar.'),
        'color_name': fields.selection([('red', 'Red'),('blue','Blue'), ('lightgreen', 'Light Green'), ('lightblue','Light Blue'), ('lightyellow', 'Light Yellow'), ('magenta', 'Magenta'),('lightcyan', 'Light Cyan'),('black', 'Black'),('lightpink', 'Light Pink'),('brown', 'Brown'),('violet', 'Violet'),('lightcoral', 'Light Coral'),('lightsalmon', 'Light Salmon'),('lavender', 'Lavender'),('wheat', 'Wheat'),('ivory', 'Ivory')],'Color in Report', required=True, help='This color will be used in the leaves summary located in Reporting\Leaves by Department.'),
        'limit': fields.boolean('Allow to Override Limit', help='If you select this check box, the system allows the employees to take more overtime than the available ones for this type and take them into account for the "Remaining Legal Overtime" defined on the employee form.'),
        'active': fields.boolean('Active',help="If the active field is set to false, it will allow you to hide the overtime type without removing it."),
        'double_validation': fields.boolean('Apply Double Validation', help="When selected, the Allocation/Leave Requests for this type require a second validation to be approved."),
        }
    _defaults = {
        'color_name': 'red',
        'active': True,
    }
    
hr_overtime_status()
class hr_overtime(osv.osv):
    _name = "hr.overtime"
    _inherit="hr.holidays"
    _columns={
        'name': fields.char('Reason', size=64),
        'date_start':fields.datetime("Date Start"),
        'date_end':fields.datetime("Date End"),
        'holiday_status_id': fields.many2one("hr.overtime.status", "Overtime Type", required=True,readonly=True, states={'draft':[('readonly',False)], 'confirm':[('readonly',False)]}),
    }
    def _check_hour(self, cr, uid, ids,context=None):
        for shift in self.browse(cr, uid, ids, context=context):
            if shift.date_start or  shift.date_end:
                if shift.date_start > shift.date_end:
                    return False
        return True
    def _check_date(self, cr, uid, ids):
        for holiday in self.browse(cr, uid, ids):
            holiday_ids = self.search(cr, uid, [('date_start', '<=', holiday.date_end), ('date_end', '>=', holiday.date_start), ('employee_id', '=', holiday.employee_id.id), ('id', '<>', holiday.id)])
            if holiday_ids:
                return False
        return True
    _constraints = [
        (_check_hour,"'Start Hour' must less than end hour or 'Start Hour' or 'End Hour' is out of range [0,24].",['hour_start','hour_end']),
        (_check_date, 'You can not have 2 overtime that overlaps on same day!', ['date']),
    ]
    def unlink(self, cr, uid, ids, context=None):
        for rec in self.browse(cr, uid, ids, context=context):
            if rec.state not in ['draft', 'cancel', 'confirm']:
                raise osv.except_osv(_('Warning!'),_('You cannot delete a leave which is in %s state.')%(rec.state))
        return super(hr_late_in, self).unlink(cr, uid, ids, context)
    def _remove_resource_overtime(self, cr, uid, ids, context=None):
        '''This method will create entry in resource calendar leave object at the time of holidays cancel/removed'''
        obj_res_leave = self.pool.get('resource.calendar.leaves')
        leave_ids = obj_res_leave.search(cr, uid, [('late_in_id', 'in', ids)], context=context)
        return obj_res_leave.unlink(cr, uid, leave_ids, context=context)
    def _create_resource_leave(self, cr, uid, leaves, context=None):
        '''This method will create entry in resource calendar leave object at the time of holidays validated '''
        obj_res_leave = self.pool.get('resource.calendar.leaves')
        for leave in leaves:
            vals = {
                'name': leave.name,
                'date_from': leave.date_start,
                'overtime_id': leave.id,
                'date_to': leave.date_end,
                'resource_id': leave.employee_id.resource_id.id,
                'calendar_id': leave.employee_id.resource_id.calendar_id.id
            }
            obj_res_leave.create(cr, uid, vals, context=context)
        return True
    def holidays_first_validate(self, cr, uid, ids, context=None):
        obj_emp = self.pool.get('hr.employee')
        ids2 = obj_emp.search(cr, uid, [('user_id', '=', uid)])
        manager = ids2 and ids2[0] or False
        self.holidays_first_validate_notificate(cr, uid, ids, context=context)
        return self.write(cr, uid, ids, {'state':'validate1', 'manager_id': manager})

    def holidays_validate(self, cr, uid, ids, context=None):
        obj_emp = self.pool.get('hr.employee')
        ids2 = obj_emp.search(cr, uid, [('user_id', '=', uid)])
        manager = ids2 and ids2[0] or False
        self.write(cr, uid, ids, {'state':'validate'})
        data_holiday = self.browse(cr, uid, ids)
        for record in data_holiday:
            if record.double_validation:
                self.write(cr, uid, [record.id], {'manager_id2': manager})
            else:
                self.write(cr, uid, [record.id], {'manager_id': manager})
            if record.holiday_type == 'employee' and record.type == 'remove':
                meeting_obj = self.pool.get('crm.meeting')
                meeting_vals = {
                    'name': record.name or _('Leave Request'),
                    'categ_ids': record.holiday_status_id.categ_id and [(6,0,[record.holiday_status_id.categ_id.id])] or [],
                    'description': record.notes,
                    'user_id': record.user_id.id,
                    'date': record.date_start,
                    'end_date': record.date_end,
                    'date_deadline': record.date_end,
                    'state': 'open',            # to block that meeting date in the calendar
                }
                meeting_id = meeting_obj.create(cr, uid, meeting_vals)
                self._create_resource_leave(cr, uid, [record], context=context)
                self.write(cr, uid, ids, {'meeting_id': meeting_id})
            elif record.holiday_type == 'category':
                emp_ids = obj_emp.search(cr, uid, [('category_ids', 'child_of', [record.category_id.id])])
                leave_ids = []
                for emp in obj_emp.browse(cr, uid, emp_ids):
                    vals = {
                        'name': record.name,
                        'type': record.type,
                        'holiday_type': 'employee',
                        'holiday_status_id': record.holiday_status_id.id,
                        'date_from': record.date_start,
                        'date_to': record.date_end,
                        'notes': record.notes,
                        'parent_id': record.id,
                        'employee_id': emp.id
                    }
                    leave_ids.append(self.create(cr, uid, vals, context=None))
                wf_service = netsvc.LocalService("workflow")
                for leave_id in leave_ids:
                    wf_service.trg_validate(uid, 'hr.holidays', leave_id, 'confirm', cr)
                    wf_service.trg_validate(uid, 'hr.holidays', leave_id, 'validate', cr)
                    wf_service.trg_validate(uid, 'hr.holidays', leave_id, 'second_validate', cr)
        return True

    def holidays_confirm(self, cr, uid, ids, context=None):
        for record in self.browse(cr, uid, ids, context=context):
            if record.employee_id and record.employee_id.parent_id and record.employee_id.parent_id.user_id:
                self.message_subscribe_users(cr, uid, [record.id], user_ids=[record.employee_id.parent_id.user_id.id], context=context)
        return self.write(cr, uid, ids, {'state': 'confirm'})
    def overtime_refuse(self, cr, uid, ids, context=None):
        obj_emp = self.pool.get('hr.employee')
        ids2 = obj_emp.search(cr, uid, [('user_id', '=', uid)])
        manager = ids2 and ids2[0] or False
        for holiday in self.browse(cr, uid, ids, context=context):
            if holiday.state == 'validate1':
                self.write(cr, uid, [holiday.id], {'state': 'refuse', 'manager_id': manager})
            else:
                self.write(cr, uid, [holiday.id], {'state': 'refuse', 'manager_id2': manager})
        self.overtime_cancel(cr, uid, ids, context=context)
        return True

    def overtime_cancel(self, cr, uid, ids, context=None):
        meeting_obj = self.pool.get('crm.meeting')
        for record in self.browse(cr, uid, ids):
            # Delete the meeting
            if record.meeting_id:
                meeting_obj.unlink(cr, uid, [record.meeting_id.id])

            # If a category that created several holidays, cancel all related
            wf_service = netsvc.LocalService("workflow")
            for request in record.linked_request_ids or []:
                wf_service.trg_validate(uid, 'hr.late.in', request.id, 'refuse', cr)

        self._remove_resource_overtime(cr, uid, ids, context=context)
        return True
    def set_to_draft(self, cr, uid, ids, context=None):
        self.write(cr, uid, ids, {
            'state': 'draft',
            'manager_id': False,
            'manager_id2': False,
        })
        wf_service = netsvc.LocalService("workflow")
        for id in ids:
            wf_service.trg_delete(uid, 'hr.overtime', id, cr)
            wf_service.trg_create(uid, 'hr.overtime', id, cr)
        to_unlink = []
        for record in self.browse(cr, uid, ids, context=context):
            for record2 in record.linked_request_ids:
                self.set_to_draft(cr, uid, [record2.id], context=context)
                to_unlink.append(record2.id)
        if to_unlink:
            self.unlink(cr, uid, to_unlink, context=context)
        return True
hr_overtime()
class resource_calendar_leaves(osv.osv):
    _inherit = "resource.calendar.leaves"
    _description = "Leave Detail"
    _columns = {
        'overtime_id': fields.many2one("hr.overtime", "Overtime Request"),
    }

resource_calendar_leaves()